﻿#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 版权所有 (c) 2023 HP NJRN 保留所有权利。
 * CLR版本：4.0.30319.42000
 * 机器名称：WEIHAN
 * 公司名称：HP
 * 命名空间：HuanTian.Service.SysService
 * 唯一标识：b96e7e23-a5e3-4848-8905-7de0be1f9f70
 * 文件名：SysDicService
 * 当前用户域：weihan
 * 
 * 创建者：wanglei
 * 创建时间：2023/5/24 14:46:50
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>


using HuanTian.Service.SysService.Dto;
using SqlSugar;

namespace HuanTian.Service;

/// <summary>
/// 系统字典服务
/// </summary>
public class SysDicService : IDynamicApiController
{
    private readonly IRepository<SysDicDetailDO> _sysDicDetail;
    private readonly IRepository<SysDicDO> _sysDic;
    private readonly ISqlSugarClient _sqlSugarClient;
    public SysDicService(IRepository<SysDicDetailDO> sysDicDetail, IRepository<SysDicDO> sysDic, ISqlSugarClient sqlSugarClient)
    {
        _sysDicDetail = sysDicDetail;
        _sysDic = sysDic;
        _sqlSugarClient = sqlSugarClient;
    }
    public async Task<IEnumerable<SysDicDetailDO>> Get([FromQuery] SysDicInput input)
    {
        long masterId = 0;
        if (!string.IsNullOrEmpty(input.Code))
        {
            var dicMaster = await _sysDic.FirstOrDefaultAsync(t => t.Code == input.Code);
            if (dicMaster == null)
            {
                throw new FriendlyException($"字典不存在{input.Code}的数据");
            }
            masterId = dicMaster.Id;
        }
        var list = await _sysDicDetail
            .WhereIf(!string.IsNullOrEmpty(input.Name), t => t.Name == input.Name)
            .WhereIf(!string.IsNullOrEmpty(input.Code), t => t.MasterId == masterId)
            .OrderBy(t => t.Order)
            .ToListAsync();
        return list;
    }
    /// <summary>
    /// 获取主表数据
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    public async Task<IEnumerable<SysDicDO>> GetMasterList([FromQuery] SysDicInput input)
    {
        var list = await _sysDic
            .WhereIf(!string.IsNullOrEmpty(input.Name), t => t.Name == input.Name)
            .WhereIf(!string.IsNullOrEmpty(input.Code), t => t.Code == input.Code)
            .ToListAsync();
        return list;
    }
    [HttpGet]
    public async Task<PageData> Page([FromQuery] SysDicPageInput input)
    {
        var list = await _sysDic
            .WhereIf(!string.IsNullOrEmpty(input.Name), t => t.Name == input.Name)
            .WhereIf(!string.IsNullOrEmpty(input.Code), t => t.Code == input.Code)
            .ToPageListAsync(input.PageNo, input.PageSize);
        return list;
    }
    public async Task<int> Add(SysDicFormInput input)
    {
        var entity = input.Adapt<SysDicDO>();
        var info = await _sysDic.FirstOrDefaultAsync(t => t.Code == input.Code);
        if (info != null)
        {
            throw new Exception("字典编码已存在");
        }
        var count = await _sysDic.InitTable(entity)
            .CallEntityMethod(t => t.CreateFunc())
            .AddAsync();
        input.Id = entity.Id;
        return count;
    }
    public async Task<int> Update(SysDicFormInput input)
    {
        var entity = input.Adapt<SysDicDO>();
        var info = await _sysDic.FirstOrDefaultAsync(t => t.Code == input.Code && t.Id != input.Id);
        if (info != null)
        {
            throw new Exception("字典编码已存在");
        }
        var count = await _sysDic.InitTable(entity)
            .UpdateAsync();
        return count;
    }
    public async Task<int> Delete(IdInput input)
    {
        var count = await _sysDic.DeleteAsync(input.Ids);
        // 删除从表数据
        count += await _sysDicDetail.DeleteAsync(t => input.Ids.Contains(t.MasterId));
        return count;
    }
    /// <summary>
    /// 字典详情新增
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    [HttpPost("DetailAdd")]
    public async Task<int> DetailAdd(SysDicDetaiLFormInput input)
    {
        var count = 0;
        // 数据过滤
        bool valueDuplicate = input.SysDicDetail.GroupBy(m => m.Value).Count() != input.SysDicDetail.Count();
        bool nameDuplicate = input.SysDicDetail.GroupBy(m => m.Name).Count() != input.SysDicDetail.Count();

        if (valueDuplicate)
        {
            throw new Exception("存在相同字典值,请修改后再试");
        }
        if (nameDuplicate)
        {
            throw new Exception("存在相同字典名称,请修改后再试");
        }
        
        // 添加数据
        if (input.SysDicDetail.Any())
        {
            count += await _sysDicDetail.InitTable(input.SysDicDetail)
            //.CallEntityMethod(t => t.CreateFunc())
            .CallEntityMethod(t => t.SetValue<SysDicDetailDO>(q => q.MasterId == input.MasterId))
            .AddAsync();
        }
        return count;
    }

    /// <summary>
    /// 字典详情修改
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    [HttpPost("DetailUpdate")]
    public async Task<int> DetailUpdate(SysDicDetaiLFormInput input)
    {
        var count = 0;
        // 数据过滤
        bool valueDuplicate = input.SysDicDetail.GroupBy(m => m.Value).Count() != input.SysDicDetail.Count();
        bool nameDuplicate = input.SysDicDetail.GroupBy(m => m.Name).Count() != input.SysDicDetail.Count();

        if (valueDuplicate)
        {
            throw new Exception("存在相同字典值,请修改后再试");
        }
        if (nameDuplicate)
        {
            throw new Exception("存在相同字典名称,请修改后再试");
        }
        // 修改数据
        if (input.SysDicDetail.Any())
        {
            count += await _sysDicDetail.InitTable(input.SysDicDetail)
            //.CallEntityMethod(t => t.CreateFunc())
            .CallEntityMethod(t => t.SetValue<SysDicDetailDO>(q => q.MasterId == input.MasterId))
            .UpdateAsync();
        }
        return count;
    }

    /// <summary>
    /// 枚举存入数据库
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [AllowAnonymous]
    public async Task<int> EnumSaveToDb()
    {
        // 获取数据库存储的枚举类型
        var dbEnumList = await _sqlSugarClient.Queryable<SysDicDO>()
            .Where(t => t.IsSys)
            .Includes(t => t.Detail)
            .Select(t => new SysDicOutput
            {
                Id = t.Id.SelectAll(),
                Detail = t.Detail
            })
            .ToListAsync();
        // 获取系统内的枚举类型
        var sysEnumList = GetEnumTypeList();

        // 获取新增的枚举类型
        var addList = sysEnumList.Where(t => !dbEnumList.Any(q => q.Code == t.Code)).ToList();

        // 获得需要修改的枚举类型
        var updateList = sysEnumList.Where(t => dbEnumList.Any(q => q.Code == t.Code)).ToList();
        // 将id赋值给updateList
        foreach (var item in updateList)
        {
            var info = dbEnumList.FirstOrDefault(q => q.Code == item.Code);
            item.Id = info?.Id ?? 0;
            item.Detail.ForEach(q => 
            {
                q.MasterId = item.Id;
                q.Id = info?.Detail.FirstOrDefault(e => e.Value == q.Value)?.Id ?? 0;
            });
        }

        // 添加新增的枚举类型
        foreach(var addInfo in addList)
        {
            var addInput = addInfo.Adapt<SysDicFormInput>();
            await Add(addInput);
            var detailInput = new SysDicDetaiLFormInput();
            detailInput.MasterId = addInput.Id;
            detailInput.SysDicDetail = addInfo.Detail;
            await DetailAdd(detailInput);
        }

        // 更新已有的枚举类型
        foreach(var updateInfo in updateList)
        {
            var updateInput = updateInfo.Adapt<SysDicFormInput>();
            await Update(updateInput);
            var detailInput = new SysDicDetaiLFormInput();
            detailInput.MasterId = updateInfo.Id;
            detailInput.SysDicDetail = updateInfo.Detail;
            await DetailUpdate(detailInput);
        }
        return addList.Count + updateList.Count;
    }

    /// <summary>
    /// 获取所有枚举类型
    /// </summary>
    /// <returns></returns>
    [NonAction]
    public List<SysDicOutput> GetEnumTypeList()
    {
        // 加载目标程序集
        var assembly = AssemblyHelper.GetAssemblyArray();
        var allTypes = assembly.SelectMany(a => a.GetTypes());
        var enumTypeList = allTypes.Where(t => t.IsEnum)
            .OrderBy(u => u.Name).ThenBy(u => u.FullName)
            .ToList();
        return enumTypeList.Select(GetEnumDescription).ToList();
    }
    /// <summary>
    /// 获取字典描述
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private SysDicOutput GetEnumDescription(Type type)
    {
        // 加载目标程序集
        var assembly = AssemblyHelper.GetAssemblyArray();
        var enumType = assembly.SelectMany(a => a.GetTypes()).FirstOrDefault(t => t.IsEnum && t.Name == type.Name);
        var docList = AssemblyHelper.GetXMLDocOfProject();
        // 获取注释文档里的枚举名称
        var enumName = $"T:{enumType.FullName}";
        var entityComment = "";
        foreach (var xmlDoc in docList)
        {
            entityComment = xmlDoc.Descendants("member")
                .FirstOrDefault(x => x.Attribute("name")?.Value == enumName)?
                .Element("summary")?.Value.Trim();

            if (!string.IsNullOrEmpty(entityComment))
                break;

        }
        return new SysDicOutput
        {
            IsSys = true,
            Code = type.Name,
            Enable = true,
            Name = entityComment ?? "",
            Detail = EnumToList((enumType ?? type))
        };
    }
    /// <summary>
    /// 将枚举转成枚举信息集合
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private List<SysDicDetailDO> EnumToList(Type type)
    {
        if (!type.IsEnum)
            throw new ArgumentException("Type '" + type.Name + "' is not an enum.");
        var arr = Enum.GetNames(type);
        var docList = AssemblyHelper.GetXMLDocOfProject();

        return arr.Select(sl =>
        {
            // 获取注释文档里的枚举名称
            var item = Enum.Parse(type, sl);
            var enumMasterName = $"F:{type}.{item.ToString()}";
            var entityComment = "";
            foreach (var xmlDoc in docList)
            {
                entityComment = xmlDoc.Descendants("member")
                    .FirstOrDefault(x => x.Attribute("name")?.Value == enumMasterName)?
                    .Element("summary")?.Value.Trim();

                if (!string.IsNullOrEmpty(entityComment))
                    break;

            }
            return new SysDicDetailDO
            {
                Name = entityComment ?? item.ToString() ?? "",
                Order = item.GetHashCode() * 10,
                Value = item.GetHashCode().ToString(),
                Code = item.ToString() ?? "",
            };
        }).ToList();
    }
}

